#ifndef __MRENDER_PRIORITY_GROUP_H__
#define __MRENDER_PRIORITY_GROUP_H__

#include <map>
#include <vector>
#include "MRenderable.h"

class CMPass;
class CMCamera;
class CMRenderQueueGroup;
class CMTechnique;




class CMRenderPriorityGroup
{
	//
	// typedef 
	//

public:

	// Comparator to order pass groups
	struct PassGroupLess
	{
		bool operator()( const CMPass* a , const CMPass* b ) const
		{
			return a < b;
		}
	};

	typedef std::vector<CMRenderable*> RenderableList;
	typedef std::map<CMPass* , RenderableList* , PassGroupLess> SolidRenderablePassMap;

	struct _RenderablePass
	{
		CMRenderable* pRenderable;
		CMPass* pPass;

		_RenderablePass( CMRenderable* pRend , CMPass* p )
			: pRenderable( pRend ) ,
			pPass( p )
		{
		}

		_RenderablePass& operator=( const _RenderablePass& rhs )
		{
			pRenderable = rhs.pRenderable;
			pPass       = rhs.pPass;

			return *this;
		}
	};
	typedef struct _RenderablePass RenderablePass;

	typedef ::std::vector<RenderablePass> TransparentRenderablePassList;

	enum _SortingMode
	{
		// Group by pass
		SM_PASS_GROUP ,
		// Sort descending camera distance
		SM_DESCENDING ,
		// Sort ascending camera distance 
		SM_ASCENDING
	};
	typedef enum _SortingMode SortingMode;

	// Comparator to order objects by descending camera distance
	struct DepthSortDescendingLess
	{
		const CMCamera* pCamera;

		DepthSortDescendingLess( const CMCamera* pCam )
			: pCamera( pCam )
		{
		}

		bool operator()( const RenderablePass& a , const RenderablePass& b ) const
		{
			if ( a.pRenderable == b.pRenderable )
			{
				// Same renderable, sort by pass hash
				return a.pPass < b.pPass;
			}
			else
			{
				// Different renderables, sort by depth
				float fADepth = a.pRenderable->GetSquaredViewDepth( pCamera );
				float fBDepth = b.pRenderable->GetSquaredViewDepth( pCamera );

				if ( fADepth == fBDepth )
				{
					// Must return deterministic result, doesn't matter what
					return a.pPass < b.pPass;
				}
				else
				{
					// Sort DESCENDING by depth (ie far objects first)
					return ( fADepth > fBDepth );
				}
			}
		}
	};

	// Comparator to order objects by descending camera distance
	struct DepthSortAscendingLess
	{
		const CMCamera* pCamera;

		DepthSortAscendingLess( const CMCamera* pCam )
			: pCamera( pCam )
		{
		}

		bool operator()( const RenderablePass& a , const RenderablePass& b ) const
		{
			if ( a.pRenderable == b.pRenderable )
			{
				// Same renderable, sort by pass hash
				return a.pPass < b.pPass;
			}
			else
			{
				// Different renderables, sort by depth
				float fADepth = a.pRenderable->GetSquaredViewDepth( pCamera );
				float fBDepth = b.pRenderable->GetSquaredViewDepth( pCamera );

				if ( fADepth == fBDepth )
				{
					// Must return deterministic result, doesn't matter what
					return a.pPass < b.pPass;
				}
				else
				{
					// Sort ASCENDING by depth (ie far objects first)
					return ( fADepth < fBDepth );
				}
			}
		}
	};

	//
	// method 
	//

public:

	// constructor
	CMRenderPriorityGroup( CMRenderQueueGroup* pParent );

	// destructor
	~CMRenderPriorityGroup( void );

	// Clears this group of renderables. 
	void Clear( bool bDestroy = false );

	// Add a renderable to this group
	void AddRenderable( CMRenderable* pRenderable , CMTechnique* pTechnique );
	void AddSolidRenderable( CMTechnique* pTechnique , CMRenderable* pRenderable , bool bIsNoShadowMap );
	void AddTransparentRenderable( CMTechnique* pTechnique , CMRenderable* pRenderable );

	// Get the collection of solid passes currently queued.
	const SolidRenderablePassMap& GetSolidNoLightPasses( void ) const { return __SolidNoLightRenderablesByPass; }
	const SolidRenderablePassMap& GetSolidLightPasses( void ) const { return __SolidLightRenderablesByPass; }
	const TransparentRenderablePassList& GetTransparentPasses( void ) const { return __TransparentRenderablesByPass; }

	// Perform any sorting that is required.
	void Sort( const CMCamera* pCamera );

	//
	// attribute 
	//

protected:

	CMRenderQueueGroup*            __pRenderQueueGroup;

	SolidRenderablePassMap         __SolidNoLightRenderablesByPass;
	SolidRenderablePassMap         __SolidLightRenderablesByPass;
	TransparentRenderablePassList  __TransparentRenderablesByPass;
};

#endif